﻿using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.IO;

namespace System
{
	public partial struct Line3G
	{
		public V3G A;
		public V3G B;
		public bool LongSide;
		public bool Valid
		{
			get
			{
				return A.Valid && B.Valid;
			}
			set
			{
				if (!value)
				{
					A = V3G.Null;
					B = V3G.Null;
				}
			}
		}
		//Longside
		public Line3G(V3G a, V3G b, bool ls)
		{
			A = a;
			B = b;
			LongSide = ls;
		}
		public override String ToString()
		{
			if (Valid)
				return A.ToString() + " - " + B.ToString();
			else
				return "<<Invalid>>";
		}
		public double Length
		{
			get
			{
				double a = V3D.Angle(A, B);
				return (V3G.EarthRadius + A._Height) * a;
			}
		}
		public V3D Dist
		{
			get
			{
				double a = V3D.Angle(A, B);
				if (a == 0)
					return V3D.Black;
				else
					return Dir * (V3G.EarthRadius + A._Height) * a;
			}
		}
		public V3D Dir
		{
			get
			{
				V3D N = ((V3D)A).Unit;
				V3D X = ((V3D)B - (V3D)A).Unit;
				return ((N % X) % N).RotY(-A.Longitude).RotX(A.Latitude);
			}
		}
		public double Heading
		{
			get
			{
				return A.GetHeading(B);
			}
		}
		public static V3G operator *(Line3G L1, Line3G L2)
		{
			V3D A1 = L1.A;
			V3D A2 = L1.B;
			V3D N1 = (A1 % A2);
			V3D B1 = L2.A;
			V3D B2 = L2.B;
			V3D N2 = (B1 % B2);

			V3D M = -(N1 % N2);
			V3D M2 = -M;

			bool InAShort = N1 * (A1 % M) > 0 && N1 * (M % A2) > 0;
			bool InBShort = N2 * (B1 % M) > 0 && N2 * (M % B2) > 0;
			if (!InAShort && !InBShort)
			{
				M = (N1 % N2).Unit;
				M2 = -M;
				InAShort = N1 * (A1 % M) > 0 && N1 * (M % A2) > 0;
				InBShort = N2 * (B1 % M) > 0 && N2 * (M % B2) > 0;
			}
			if (L1.LongSide ^ InAShort && L2.LongSide ^ InBShort)
			{
				if ((L1.LongSide && !InAShort) && (L2.LongSide && !InBShort))
					return M2;
				else
					return M;
			}
			else
				return V3G.Null;
		}

		public V3G NearestPoint(V3G P)
		{
			V3G M = this * new Line3G(P, P.AddLocal(1, A.GetHeading(B) + 90), true);
			if (M.Valid)
				return M;
			else if ((M = new Line3G(A, B, !LongSide) * new Line3G(P, P.AddLocal(1, A.GetHeading(B) + 90), true)).Valid)
				return M;
			else if ((M = new Line3G(A, B, !LongSide) * new Line3G(P, P.AddLocal(-1, A.GetHeading(B) + 90), true)).Valid)
				return M;
			else
				return this * new Line3G(P, P.AddLocal(-1, A.GetHeading(B) + 90), true);
		}
	}
}